/*  Back Orifice 2000 - Remote Administration Suite
    Copyright (C) 1999, Cult Of The Dead Cow

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

	The author of this program may be contacted at dildog@l0pht.com. */

#ifndef __INC_LZHCOMPRESS_H
#define __INC_LZHCOMPRESS_H

#ifdef _SOLARIS
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
//typedef unsigned long HANDLE;
#else
#include<windows.h>
#include<limits.h>
#endif

#define N       4096    /* buffer size */
#define F       60  /* lookahead buffer size */
#define THRESHOLD   2
#define NIL     N   /* leaf of tree */
#define N_CHAR      (256 - THRESHOLD + F)
                /* kinds of characters (character code = 0..N_CHAR-1) */
#define T       (N_CHAR * 2 - 1)    /* size of table */
#define R       (T - 1)         /* position of root */
#define MAX_FREQ    0x8000      /* updates tree when the */

//##ModelId=3AAC61150004
class CLzhCompress {
private:
	
	//##ModelId=3AAC62CA0107
	unsigned long textsize;
	//##ModelId=3AAC62CA00CB
	unsigned long codesize;

	// LZSS compression

	//##ModelId=3AAC61150024
	BYTE text_buf[N + F - 1];
	//##ModelId=3AAC62CA008F
	short match_position;
	//##ModelId=3AAC62CA0053
	short match_length;
	//##ModelId=3AAC62CA0021
	short lson[N + 1];
	//##ModelId=3AAC62C903CC
	short rson[N + 257];
	//##ModelId=3AAC62C90390
	short dad[N + 1];

	// Huffman coding

	//##ModelId=3AAC61150023
	WORD freq[T + 1];	/* frequency table */
	//##ModelId=3AAC61150022
	short prnt[T + N_CHAR];	/* pointers to parent nodes, except for the */
							/* elements [T..T + N_CHAR - 1] which are used to get */
							/* the positions of leaves corresponding to the codes. */
	//##ModelId=3AAC6115001A
	short son[T];				/* pointers to child nodes (son[], son[] + 1) */

	//##ModelId=3AAC61150019
	WORD getbuf;
	//##ModelId=3AAC61150018
	BYTE getlen;
	
	//##ModelId=3AAC61150010
	WORD putbuf;
	//##ModelId=3AAC6115000F
	BYTE putlen;

	//##ModelId=3AAC62C9034A
	WORD code;
	//##ModelId=3AAC62C90318
	WORD len;


	// Various read/write things
#ifdef _SOLARIS
	//##ModelId=3AAC62C902DC
	int hFileIn;
	//##ModelId=3AAC62C902A0
	int hFileOut;
#else
	HANDLE hFileIn;
	HANDLE hFileOut;
#endif
	//##ModelId=3AAC62C90264
	BYTE *pMemIn;
	//##ModelId=3AAC62C90228
	BYTE *pMemOut;
	//##ModelId=3AAC62C901EC
	int nMemInSize;
	//##ModelId=3AAC62C901BA
	int nMemOutSize;
	//##ModelId=3AAC62C9017E
	int nMemInOff;
	//##ModelId=3AAC62C90142
	int nMemOutOff;
	//##ModelId=3AAC6115000E
	int freeze_type;

protected:

	//##ModelId=3AAC6115009E
	void InitTree(void);				// initialize trees 
	//##ModelId=3AAC6115009C
	void InsertNode(short r);			// insert to tree 
	//##ModelId=3AAC6115009A
	void DeleteNode(short p);			// remove from tree 
	//##ModelId=3AAC61150094
	WORD GetBit(void);				// get one bit 
	//##ModelId=3AAC61150092
	WORD GetByte(void);				// get one byte 
	//##ModelId=3AAC6115008A
	void Putcode(short l, WORD c); // output c bits of code 
	//##ModelId=3AAC61150088
	void StartHuff(void);
	//##ModelId=3AAC61150086
	void reconst(void);
	//##ModelId=3AAC6115007F
	void update(short c);
	//##ModelId=3AAC6115007D
	void EncodeChar(WORD c);
	//##ModelId=3AAC61150076
	void EncodePosition(WORD c);
	//##ModelId=3AAC61150074
	void EncodeEnd(void);
	//##ModelId=3AAC61150072
	short DecodeChar(void);
	//##ModelId=3AAC6115006B
	short DecodePosition(void);
	//##ModelId=3AAC61150069
	void Encode(void);				// compression
	//##ModelId=3AAC61150064
	void Decode(void);				// recover 

	//##ModelId=3AAC61150061
	int fnc_read_file(BYTE *pBuffer, int nLen);
	//##ModelId=3AAC6115005E
	int fnc_write_file(BYTE *pBuffer, int nLen);
	//##ModelId=3AAC61150059
	int fnc_read_memory(BYTE *pBuffer, int nLen);
	//##ModelId=3AAC61150056
	int fnc_write_memory(BYTE *pBuffer, int nLen);
	//##ModelId=3AAC6115004F
	int fnc_write(BYTE *ptr, int len);
	//##ModelId=3AAC6115004C
	int fnc_read(BYTE *ptr, int len);

	//##ModelId=3AAC6115004A
	int fnc_getc(void);
	//##ModelId=3AAC61150043
	int fnc_putc(int val);
	//##ModelId=3AAC61150041
	int lzh_freeze(void);
	
public:
	//##ModelId=3AAC6115003D
	unsigned long GetOutputSize(); //call after lzh_freeze_memory to get output size
	//##ModelId=3AAC6115003E
	unsigned long GetOutputSize(void *pInBuffer); //call before lzh_melt_memory to get output size
	//##ModelId=3AAC6115003A
	int lzh_freeze_file(char *szInFile, char *szOutFile);
	//##ModelId=3AAC61150033
	int lzh_freeze_memory(void *pInBuffer, int nInBufLen, void *pOutBuf, int nOutBufLen);
	//##ModelId=3AAC61150030
	int lzh_melt_file(char *szInFile, char *szOutFile);
	//##ModelId=3AAC61150025
	int lzh_melt_memory(void *pInBuffer, int nInBufLen, void *pOutBuf, int nOutBufLen);
};

inline unsigned long CLzhCompress::GetOutputSize()
{
	return codesize+4;
}

inline unsigned long CLzhCompress::GetOutputSize(void *pInBuffer)
{
	return ((unsigned long)*((char*)pInBuffer)) | (((unsigned long)*((char*)pInBuffer+1))<<8) |
	       (((unsigned long)*((char*)pInBuffer+2))<<16) | (((unsigned long)*((char*)pInBuffer+3))<<24);
}

#endif
